home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / gawk-3.000 / gawk-3 / gawk-3.0.0 / io.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-29  |  38.7 KB  |  1,702 lines

  1. /*
  2.  * io.c --- routines for dealing with input and output and records
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989, 1991-1995 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Programming Language.
  10.  * 
  11.  * GAWK is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  * 
  16.  * GAWK is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  * 
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
  24.  */
  25.  
  26. #include "awk.h"
  27.  
  28. #ifdef HAVE_SYS_PARAM_H
  29. #include <sys/param.h>
  30. #endif /* HAVE_SYS_PARAM_H */
  31.  
  32. #ifdef HAVE_SYS_WAIT_H
  33. #include <sys/wait.h>
  34. #endif /* HAVE_SYS_WAIT_H */
  35.  
  36. #ifndef O_RDONLY
  37. #include <fcntl.h>
  38. #endif
  39.  
  40. #include <assert.h>
  41.  
  42. #if ! defined(S_ISREG) && defined(S_IFREG)
  43. #define    S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
  44. #endif
  45.  
  46. #if ! defined(S_ISDIR) && defined(S_IFDIR)
  47. #define    S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
  48. #endif
  49.  
  50. #ifndef ENFILE
  51. #define ENFILE EMFILE
  52. #endif
  53.  
  54. #ifdef atarist
  55. #include <stddef.h>
  56. #endif
  57.  
  58. #if defined(MSDOS) || defined(OS2)
  59. #define PIPES_SIMULATED
  60. #endif
  61.  
  62. static IOBUF *nextfile P((int skipping));
  63. static int inrec P((IOBUF *iop));
  64. static int iop_close P((IOBUF *iop));
  65. struct redirect *redirect P((NODE *tree, int *errflg));
  66. static void close_one P((void));
  67. static int close_redir P((struct redirect *rp, int exitwarn));
  68. #ifndef PIPES_SIMULATED
  69. static int wait_any P((int interesting));
  70. #endif
  71. static IOBUF *gawk_popen P((char *cmd, struct redirect *rp));
  72. static IOBUF *iop_open P((const char *file, const char *how));
  73. static int gawk_pclose P((struct redirect *rp));
  74. static int do_pathopen P((const char *file));
  75. static int get_a_record P((char **out, IOBUF *iop, int rs, Regexp *RSre, int *errcode));
  76. static int str2mode P((const char *mode));
  77. static void spec_setup P((IOBUF *iop, int len, int allocate));
  78. static int specfdopen P((IOBUF *iop, const char *name, const char *mode));
  79. static int pidopen P((IOBUF *iop, const char *name, const char *mode));
  80. static int useropen P((IOBUF *iop, const char *name, const char *mode));
  81.  
  82. #if defined (MSDOS) && !defined (__GO32__)
  83. #include "popen.h"
  84. #define popen(c, m)    os_popen(c, m)
  85. #define pclose(f)    os_pclose(f)
  86. #else
  87. #if defined (OS2)    /* OS/2, but not family mode */
  88. #if defined (_MSC_VER)
  89. #define popen(c, m)    _popen(c, m)
  90. #define pclose(f)    _pclose(f)
  91. #endif
  92. #else
  93. extern FILE    *popen();
  94. #endif
  95. #endif
  96.  
  97. static struct redirect *red_head = NULL;
  98. static NODE *RS;
  99. static Regexp *RS_regexp;
  100.  
  101. int RS_is_null;
  102.  
  103. extern int output_is_tty;
  104. extern NODE *ARGC_node;
  105. extern NODE *ARGV_node;
  106. extern NODE *ARGIND_node;
  107. extern NODE *ERRNO_node;
  108. extern NODE **fields_arr;
  109.  
  110. static jmp_buf filebuf;        /* for do_nextfile() */
  111.  
  112. /* do_nextfile --- implement gawk "next file" extension */
  113.  
  114. void
  115. do_nextfile()
  116. {
  117.     (void) nextfile(TRUE);
  118.     longjmp(filebuf, 1);
  119. }
  120.  
  121. /* nextfile --- move to the next input data file */
  122.  
  123. static IOBUF *
  124. nextfile(skipping)
  125. int skipping;
  126. {
  127.     static long i = 1;
  128.     static int files = 0;
  129.     NODE *arg;
  130.     static IOBUF *curfile = NULL;
  131.  
  132.     if (skipping) {
  133.         if (curfile != NULL)
  134.             iop_close(curfile);
  135.         curfile = NULL;
  136.         return NULL;
  137.     }
  138.     if (curfile != NULL) {
  139.         if (curfile->cnt == EOF) {
  140.             (void) iop_close(curfile);
  141.             curfile = NULL;
  142.         } else
  143.             return curfile;
  144.     }
  145.     for (; i < (long) (ARGC_node->lnode->numbr); i++) {
  146.         arg = *assoc_lookup(ARGV_node, tmp_number((AWKNUM) i));
  147.         if (arg->stlen == 0)
  148.             continue;
  149.         arg->stptr[arg->stlen] = '\0';
  150.         if (! do_traditional) {
  151.             unref(ARGIND_node->var_value);
  152.             ARGIND_node->var_value = make_number((AWKNUM) i);
  153.         }
  154.         if (! arg_assign(arg->stptr)) {
  155.             files++;
  156.             curfile = iop_open(arg->stptr, "r");
  157.             if (curfile == NULL)
  158.                 fatal("cannot open file `%s' for reading (%s)",
  159.                     arg->stptr, strerror(errno));
  160.                 /* NOTREACHED */
  161.             /* This is a kludge.  */
  162.             unref(FILENAME_node->var_value);
  163.             FILENAME_node->var_value = dupnode(arg);
  164.             FNR = 0;
  165.             i++;
  166.             break;
  167.         }
  168.     }
  169.     if (files == 0) {
  170.         files++;
  171.         /* no args. -- use stdin */
  172.         /* FNR is init'ed to 0 */
  173.         FILENAME_node->var_value = make_string("-", 1);
  174.         curfile = iop_alloc(fileno(stdin), "stdin");
  175.     }
  176.     return curfile;
  177. }
  178.  
  179. /* set_FNR --- update internal FNR from awk variable */
  180.  
  181. void
  182. set_FNR()
  183. {
  184.     FNR = (long) FNR_node->var_value->numbr;
  185. }
  186.  
  187. /* set_NR --- update internal NR from awk variable */
  188.  
  189. void
  190. set_NR()
  191. {
  192.     NR = (long) NR_node->var_value->numbr;
  193. }
  194.  
  195. /* inrec --- This reads in a record from the input file */
  196.  
  197. static int
  198. inrec(iop)
  199. IOBUF *iop;
  200. {
  201.     char *begin;
  202.     register int cnt;
  203.     int retval = 0;
  204.  
  205.     cnt = get_a_record(&begin, iop, RS->stptr[0], RS_regexp, NULL);
  206.     if (cnt == EOF) {
  207.         cnt = 0;
  208.         retval = 1;
  209.     } else {
  210.         NR += 1;
  211.         FNR += 1;
  212.         set_record(begin, cnt, TRUE);
  213.     }
  214.  
  215.     return retval;
  216. }
  217.  
  218. /* iop_close --- close an open IOP */
  219.  
  220. static int
  221. iop_close(iop)
  222. IOBUF *iop;
  223. {
  224.     int ret;
  225.  
  226.     if (iop == NULL)
  227.         return 0;
  228.     errno = 0;
  229.  
  230. #ifdef _CRAY
  231.     /* Work around bug in UNICOS popen */
  232.     if (iop->fd < 3)
  233.         ret = 0;
  234.     else
  235. #endif
  236.     /* save these for re-use; don't free the storage */
  237.     if ((iop->flag & IOP_IS_INTERNAL) != 0) {
  238.         iop->off = iop->buf;
  239.         iop->end = iop->buf + strlen(iop->buf);
  240.         iop->cnt = 0;
  241.         iop->secsiz = 0;
  242.         return 0;
  243.     }
  244.  
  245.     /* Don't close standard files or else crufty code elsewhere will lose */
  246.     if (iop->fd == fileno(stdin)
  247.         || iop->fd == fileno(stdout)
  248.         || iop->fd == fileno(stderr))
  249.         ret = 0;
  250.     else
  251.         ret = close(iop->fd);
  252.     if (ret == -1)
  253.         warning("close of fd %d (`%s') failed (%s)", iop->fd,
  254.                 iop->name, strerror(errno));
  255.     if ((iop->flag & IOP_NO_FREE) == 0) {
  256.         /*
  257.          * be careful -- $0 may still reference the buffer even though
  258.          * an explicit close is being done; in the future, maybe we
  259.          * can do this a bit better
  260.          */
  261.         if (iop->buf) {
  262.             if ((fields_arr[0]->stptr >= iop->buf)
  263.                 && (fields_arr[0]->stptr < iop->end)) {
  264.                 NODE *t;
  265.     
  266.                 t = make_string(fields_arr[0]->stptr,
  267.                         fields_arr[0]->stlen);
  268.                 unref(fields_arr[0]);
  269.                 fields_arr [0] = t;
  270.                 reset_record();
  271.             }
  272.               free(iop->buf);
  273.         }
  274.         free((char *) iop);
  275.     }
  276.     return ret == -1 ? 1 : 0;
  277. }
  278.  
  279. /* do_input --- the main input processing loop */
  280.  
  281. void
  282. do_input()
  283. {
  284.     IOBUF *iop;
  285.     extern int exiting;
  286.  
  287.     (void) setjmp(filebuf);    /* for `nextfile' */
  288.  
  289.     while ((iop = nextfile(FALSE)) != NULL) {
  290.         if (inrec(iop) == 0)
  291.             while (interpret(expression_value) && inrec(iop) == 0)
  292.                 continue;
  293. #ifdef C_ALLOCA
  294.         /* recover any space from C based alloca */
  295.         (void) alloca(0);
  296. #endif
  297.         if (exiting)
  298.             break;
  299.     }
  300. }
  301.  
  302. /* redirect --- Redirection for printf and print commands */
  303.  
  304. struct redirect *
  305. redirect(tree, errflg)
  306. NODE *tree;
  307. int *errflg;
  308. {
  309.     register NODE *tmp;
  310.     register struct redirect *rp;
  311.     register char *str;
  312.     int tflag = 0;
  313.     int outflag = 0;
  314.     const char *direction = "to";
  315.     const char *mode;
  316.     int fd;
  317.     const char *what = NULL;
  318.  
  319.     switch (tree->type) {
  320.     case Node_redirect_append:
  321.         tflag = RED_APPEND;
  322.         /* FALL THROUGH */
  323.     case Node_redirect_output:
  324.         outflag = (RED_FILE|RED_WRITE);
  325.         tflag |= outflag;
  326.         if (tree->type == Node_redirect_output)
  327.             what = ">";
  328.         else
  329.             what = ">>";
  330.         break;
  331.     case Node_redirect_pipe:
  332.         tflag = (RED_PIPE|RED_WRITE);
  333.         what = "|";
  334.         break;
  335.     case Node_redirect_pipein:
  336.         tflag = (RED_PIPE|RED_READ);
  337.         what = "|";
  338.         break;
  339.     case Node_redirect_input:
  340.         tflag = (RED_FILE|RED_READ);
  341.         what = "<";
  342.         break;
  343.     default:
  344.         fatal("invalid tree type %d in redirect()", tree->type);
  345.         break;
  346.     }
  347.     tmp = tree_eval(tree->subnode);
  348.     if (do_lint && (tmp->flags & STR) == 0)
  349.         warning("expression in `%s' redirection only has numeric value",
  350.             what);
  351.     tmp = force_string(tmp);
  352.     str = tmp->stptr;
  353.     if (str == NULL || *str == '\0')
  354.         fatal("expression for `%s' redirection has null string value",
  355.             what);
  356.     if (do_lint
  357.         && (STREQN(str, "0", tmp->stlen) || STREQN(str, "1", tmp->stlen)))
  358.         warning("filename `%s' for `%s' redirection may be result of logical expression", str, what);
  359.     for (rp = red_head; rp != NULL; rp = rp->next)
  360.         if (strlen(rp->value) == tmp->stlen
  361.             && STREQN(rp->value, str, tmp->stlen)
  362.             && ((rp->flag & ~(RED_NOBUF|RED_EOF)) == tflag
  363.             || (outflag != 0
  364.                 && (rp->flag & (RED_FILE|RED_WRITE)) == outflag)))
  365.             break;
  366.     if (rp == NULL) {
  367.         emalloc(rp, struct redirect *, sizeof(struct redirect),
  368.             "redirect");
  369.         emalloc(str, char *, tmp->stlen+1, "redirect");
  370.         memcpy(str, tmp->stptr, tmp->stlen);
  371.         str[tmp->stlen] = '\0';
  372.         rp->value = str;
  373.         rp->flag = tflag;
  374.         rp->fp = NULL;
  375.         rp->iop = NULL;
  376.         rp->pid = 0;    /* unlikely that we're worried about init */
  377.         rp->status = 0;
  378.         /* maintain list in most-recently-used first order */
  379.         if (red_head != NULL)
  380.             red_head->prev = rp;
  381.         rp->prev = NULL;
  382.         rp->next = red_head;
  383.         red_head = rp;
  384.     }
  385.     while (rp->fp == NULL && rp->iop == NULL) {
  386.         if (rp->flag & RED_EOF)
  387.             /*
  388.              * encountered EOF on file or pipe -- must be cleared
  389.              * by explicit close() before reading more
  390.              */
  391.             return rp;
  392.         mode = NULL;
  393.         errno = 0;
  394.         switch (tree->type) {
  395.         case Node_redirect_output:
  396.             mode = "w";
  397.             if ((rp->flag & RED_USED) != 0)
  398.                 mode = "a";
  399.             break;
  400.         case Node_redirect_append:
  401.             mode = "a";
  402.             break;
  403.         case Node_redirect_pipe:
  404.             if ((rp->fp = popen(str, "w")) == NULL)
  405.                 fatal("can't open pipe (\"%s\") for output (%s)",
  406.                     str, strerror(errno));
  407.             rp->flag |= RED_NOBUF;
  408.             break;
  409.         case Node_redirect_pipein:
  410.             direction = "from";
  411.             if (gawk_popen(str, rp) == NULL)
  412.                 fatal("can't open pipe (\"%s\") for input (%s)",
  413.                     str, strerror(errno));
  414.             break;
  415.         case Node_redirect_input:
  416.             direction = "from";
  417.             rp->iop = iop_open(str, "r");
  418.             break;
  419.         default:
  420.             cant_happen();
  421.         }
  422.         if (mode != NULL) {
  423.             fd = devopen(str, mode);
  424.             if (fd > INVALID_HANDLE) {
  425.                 if (fd == fileno(stdin))
  426.                     rp->fp = stdin;
  427.                 else if (fd == fileno(stdout))
  428.                     rp->fp = stdout;
  429.                 else if (fd == fileno(stderr))
  430.                     rp->fp = stderr;
  431.                 else {
  432.                     rp->fp = fdopen(fd, (char *) mode);
  433.                     /* don't leak file descriptors */
  434.                     if (rp->fp == NULL)
  435.                         close(fd);
  436.                 }
  437.                 if (rp->fp != NULL && isatty(fd))
  438.                     rp->flag |= RED_NOBUF;
  439.             }
  440.         }
  441.         if (rp->fp == NULL && rp->iop == NULL) {
  442.             /* too many files open -- close one and try again */
  443.             if (errno == EMFILE || errno == ENFILE)
  444.                 close_one();
  445.             else {
  446.                 /*
  447.                  * Some other reason for failure.
  448.                  *
  449.                  * On redirection of input from a file,
  450.                  * just return an error, so e.g. getline
  451.                  * can return -1.  For output to file,
  452.                  * complain. The shell will complain on
  453.                  * a bad command to a pipe.
  454.                  */
  455.                 if (errflg != NULL)
  456.                     *errflg = errno;
  457.                 if (tree->type == Node_redirect_output
  458.                     || tree->type == Node_redirect_append)
  459.                     fatal("can't redirect %s `%s' (%s)",
  460.                         direction, str, strerror(errno));
  461.                 else {
  462.                     free_temp(tmp);
  463.                     return NULL;
  464.                 }
  465.             }
  466.         }
  467.     }
  468.     free_temp(tmp);
  469.     return rp;
  470. }
  471.  
  472. /* getredirect --- find the struct redirect for this file or pipe */
  473.  
  474. struct redirect *
  475. getredirect(str, len)
  476. char *str;
  477. int len;
  478. {
  479.     struct redirect *rp;
  480.  
  481.     for (rp = red_head; rp != NULL; rp = rp->next)
  482.         if (strlen(rp->value) == len && STREQN(rp->value, str, len))
  483.             return rp;
  484.  
  485.     return NULL;
  486. }
  487.  
  488. /* close_one --- temporarily close an open file to re-use the fd */
  489.  
  490. static void
  491. close_one()
  492. {
  493.     register struct redirect *rp;
  494.     register struct redirect *rplast = NULL;
  495.  
  496.     /* go to end of list first, to pick up least recently used entry */
  497.     for (rp = red_head; rp != NULL; rp = rp->next)
  498.         rplast = rp;
  499.     /* now work back up through the list */
  500.     for (rp = rplast; rp != NULL; rp = rp->prev)
  501.         if (rp->fp != NULL && (rp->flag & RED_FILE) != 0) {
  502.             rp->flag |= RED_USED;
  503.             errno = 0;
  504.             if (/* do_lint && */ fclose(rp->fp) != 0)
  505.                 warning("close of \"%s\" failed (%s).",
  506.                     rp->value, strerror(errno));
  507.             rp->fp = NULL;
  508.             break;
  509.         }
  510.     if (rp == NULL)
  511.         /* surely this is the only reason ??? */
  512.         fatal("too many pipes or input files open"); 
  513. }
  514.  
  515. /* do_close --- completely close an open file or pipe */
  516.  
  517. NODE *
  518. do_close(tree)
  519. NODE *tree;
  520. {
  521.     NODE *tmp;
  522.     register struct redirect *rp;
  523.  
  524.     tmp = force_string(tree_eval(tree->subnode));
  525.     for (rp = red_head; rp != NULL; rp = rp->next) {
  526.         if (strlen(rp->value) == tmp->stlen
  527.             && STREQN(rp->value, tmp->stptr, tmp->stlen))
  528.             break;
  529.     }
  530.     free_temp(tmp);
  531.     if (rp == NULL) /* no match */
  532.         return tmp_number((AWKNUM) 0.0);
  533.     fflush(stdout);    /* synchronize regular output */
  534.     tmp = tmp_number((AWKNUM) close_redir(rp, FALSE));
  535.     rp = NULL;
  536.     return tmp;
  537. }
  538.  
  539. /* close_redir --- close an open file or pipe */
  540.  
  541. static int
  542. close_redir(rp, exitwarn)
  543. register struct redirect *rp;
  544. int exitwarn;
  545. {
  546.     int status = 0;
  547.     char *what;
  548.  
  549.     if (rp == NULL)
  550.         return 0;
  551.     if (rp->fp == stdout || rp->fp == stderr)
  552.         return 0;
  553.     errno = 0;
  554.     if ((rp->flag & (RED_PIPE|RED_WRITE)) == (RED_PIPE|RED_WRITE))
  555.         status = pclose(rp->fp);
  556.     else if (rp->fp != NULL)
  557.         status = fclose(rp->fp);
  558.     else if (rp->iop != NULL) {
  559.         if ((rp->flag & RED_PIPE) != 0)
  560.             status = gawk_pclose(rp);
  561.         else {
  562.             status = iop_close(rp->iop);
  563.             rp->iop = NULL;
  564.         }
  565.     }
  566.  
  567.     what = ((rp->flag & RED_PIPE) != 0) ? "pipe" : "file";
  568.  
  569.     if (exitwarn) 
  570.         warning("no explicit close of %s `%s' provided",
  571.             what, rp->value);
  572.  
  573.     /* SVR4 awk checks and warns about status of close */
  574.     if (do_lint && status != 0) {
  575.         char *s = strerror(errno);
  576.  
  577.         /*
  578.          * Too many people have complained about this.
  579.          * As of 2.15.6, it is now under lint control.
  580.          */
  581.         if (do_lint)
  582.             warning("failure status (%d) on %s close of \"%s\" (%s)",
  583.                 status, what, rp->value, s);
  584.  
  585.         if (! do_traditional) {
  586.             /* set ERRNO too so that program can get at it */
  587.             unref(ERRNO_node->var_value);
  588.             ERRNO_node->var_value = make_string(s, strlen(s));
  589.         }
  590.     }
  591.     if (rp->next != NULL)
  592.         rp->next->prev = rp->prev;
  593.     if (rp->prev != NULL)
  594.         rp->prev->next = rp->next;
  595.     else
  596.         red_head = rp->next;
  597.     free(rp->value);
  598.     free((char *) rp);
  599.     return status;
  600. }
  601.  
  602. /* flush_io --- flush all open output files */
  603.  
  604. int
  605. flush_io()
  606. {
  607.     register struct redirect *rp;
  608.     int status = 0;
  609.  
  610.     errno = 0;
  611.     if (fflush(stdout)) {
  612.         warning("error writing standard output (%s)", strerror(errno));
  613.         status++;
  614.     }
  615.     if (fflush(stderr)) {
  616. #ifndef __amigados__  /* HACK (fnf) */
  617.         warning("error writing standard error (%s)", strerror(errno));
  618.         status++;
  619. #endif
  620.     }
  621.     for (rp = red_head; rp != NULL; rp = rp->next)
  622.         /* flush both files and pipes, what the heck */
  623.         if ((rp->flag & RED_WRITE) && rp->fp != NULL) {
  624.             if (fflush(rp->fp)) {
  625.                 warning("%s flush of \"%s\" failed (%s).",
  626.                     (rp->flag  & RED_PIPE) ? "pipe" :
  627.                     "file", rp->value, strerror(errno));
  628.                 status++;
  629.             }
  630.         }
  631.     return status;
  632. }
  633.  
  634. /* close_io --- close all open files, called when exiting */
  635.  
  636. int
  637. close_io()
  638. {
  639.     register struct redirect *rp;
  640.     register struct redirect *next;
  641.     int status = 0;
  642.  
  643.     errno = 0;
  644.     for (rp = red_head; rp != NULL; rp = next) {
  645.         next = rp->next;
  646.         /*
  647.          * close_redir() will print a message if needed
  648.          * if do_lint, warn about lack of explicit close
  649.          */
  650.         if (close_redir(rp, do_lint))
  651.             status++;
  652.         rp = NULL;
  653.     }
  654.     /*
  655.      * Some of the non-Unix os's have problems doing an fclose
  656.      * on stdout and stderr.  Since we don't really need to close
  657.      * them, we just flush them, and do that across the board.
  658.      */
  659.     if (fflush(stdout)) {
  660.         warning("error writing standard output (%s)", strerror(errno));
  661.         status++;
  662.     }
  663.     if (fflush(stderr)) {
  664. #ifndef __amigados__  /* HACK (fnf) */
  665.         warning("error writing standard error (%s)", strerror(errno));
  666.         status++;
  667. #endif
  668.     }
  669.     return status;
  670. }
  671.  
  672. /* str2mode --- convert a string mode to an integer mode */
  673.  
  674. static int
  675. str2mode(mode)
  676. const char *mode;
  677. {
  678.     int ret;
  679.  
  680.     switch(mode[0]) {
  681.     case 'r':
  682.         ret = O_RDONLY;
  683.         break;
  684.  
  685.     case 'w':
  686.         ret = O_WRONLY|O_CREAT|O_TRUNC;
  687.         break;
  688.  
  689.     case 'a':
  690.         ret = O_WRONLY|O_APPEND|O_CREAT;
  691.         break;
  692.  
  693.     default:
  694.         ret = 0;        /* lint */
  695.         cant_happen();
  696.     }
  697.     return ret;
  698. }
  699.  
  700. /* devopen --- handle /dev/std{in,out,err}, /dev/fd/N, regular files */
  701.  
  702. /*
  703.  * This separate version is still needed for output, since file and pipe
  704.  * output is done with stdio. iop_open() handles input with IOBUFs of
  705.  * more "special" files.  Those files are not handled here since it makes
  706.  * no sense to use them for output.
  707.  */
  708.  
  709. int
  710. devopen(name, mode)
  711. const char *name, *mode;
  712. {
  713.     int openfd;
  714.     const char *cp;
  715.     char *ptr;
  716.     int flag = 0;
  717.     struct stat buf;
  718.     extern double strtod();
  719.  
  720.     flag = str2mode(mode);
  721.  
  722.     if (STREQ(name, "-"))
  723.         openfd = fileno(stdin);
  724.     else
  725.         openfd = INVALID_HANDLE;
  726.  
  727.     if (do_traditional)
  728.         goto strictopen;
  729.  
  730.     if ((openfd = os_devopen(name, flag)) >= 0)
  731.         return openfd;
  732.  
  733.     if (STREQN(name, "/dev/", 5) && stat((char *) name, &buf) == -1) {
  734.         cp = name + 5;
  735.         
  736.         if (STREQ(cp, "stdin") && (flag & O_RDONLY) == O_RDONLY)
  737.             openfd = fileno(stdin);
  738.         else if (STREQ(cp, "stdout") && (flag & O_WRONLY) == O_WRONLY)
  739.             openfd = fileno(stdout);
  740.         else if (STREQ(cp, "stderr") && (flag & O_WRONLY) == O_WRONLY)
  741.             openfd = fileno(stderr);
  742.         else if (STREQN(cp, "fd/", 3)) {
  743.             cp += 3;
  744.             openfd = (int) strtod(cp, &ptr);
  745.             if (openfd <= INVALID_HANDLE || ptr == cp)
  746.                 openfd = INVALID_HANDLE;
  747.         }
  748.     }
  749.  
  750. strictopen:
  751.     if (openfd == INVALID_HANDLE)
  752.         openfd = open(name, flag, 0666);
  753.     if (openfd != INVALID_HANDLE && fstat(openfd, &buf) > 0) 
  754.         if (S_ISDIR(buf.st_mode))
  755.             fatal("file `%s' is a directory", name);
  756.     return openfd;
  757. }
  758.  
  759.  
  760. /* spec_setup --- setup an IOBUF for a special internal file */
  761.  
  762. static void
  763. spec_setup(iop, len, allocate)
  764. IOBUF *iop;
  765. int len;
  766. int allocate;
  767. {
  768.     char *cp;
  769.  
  770.     if (allocate) {
  771.         emalloc(cp, char *, len+2, "spec_setup");
  772.         iop->buf = cp;
  773.     } else {
  774.         len = strlen(iop->buf);
  775.         iop->buf[len++] = '\n';    /* get_a_record clobbered it */
  776.         iop->buf[len] = '\0';    /* just in case */
  777.     }
  778.     iop->off = iop->buf;
  779.     iop->cnt = 0;
  780.     iop->secsiz = 0;
  781.     iop->size = len;
  782.     iop->end = iop->buf + len;
  783.     iop->fd = -1;
  784.     iop->flag = IOP_IS_INTERNAL;
  785. }
  786.  
  787. /* specfdopen --- open an fd special file */
  788.  
  789. static int
  790. specfdopen(iop, name, mode)
  791. IOBUF *iop;
  792. const char *name, *mode;
  793. {
  794.     int fd;
  795.     IOBUF *tp;
  796.  
  797.     fd = devopen(name, mode);
  798.     if (fd == INVALID_HANDLE)
  799.         return INVALID_HANDLE;
  800.     tp = iop_alloc(fd, name);
  801.     if (tp == NULL) {
  802.         /* don't leak fd's */
  803.         close(fd);
  804.         return INVALID_HANDLE;
  805.     }
  806.     *iop = *tp;
  807.     iop->flag |= IOP_NO_FREE;
  808.     free(tp);
  809.     return 0;
  810. }
  811.  
  812. #ifdef GETPGRP_VOID
  813. #define getpgrp_arg() /* nothing */
  814. #else
  815. #define getpgrp_arg() getpid()
  816. #endif
  817.  
  818. /* pidopen --- "open" /dev/pid, /dev/ppid, and /dev/pgrpid */
  819.  
  820. static int
  821. pidopen(iop, name, mode)
  822. IOBUF *iop;
  823. const char *name, *mode;
  824. {
  825.     char tbuf[BUFSIZ];
  826.     int i;
  827.  
  828.     if (name[6] == 'g')
  829.         sprintf(tbuf, "%d\n", getpgrp(getpgrp_arg()));
  830.     else if (name[6] == 'i')
  831.         sprintf(tbuf, "%d\n", getpid());
  832.     else
  833.         sprintf(tbuf, "%d\n", getppid());
  834.     i = strlen(tbuf);
  835.     spec_setup(iop, i, TRUE);
  836.     strcpy(iop->buf, tbuf);
  837.     return 0;
  838. }
  839.  
  840. /* useropen --- "open" /dev/user */
  841.  
  842. /*
  843.  * /dev/user creates a record as follows:
  844.  *    $1 = getuid()
  845.  *    $2 = geteuid()
  846.  *    $3 = getgid()
  847.  *    $4 = getegid()
  848.  * If multiple groups are supported, then $5 through $NF are the
  849.  * supplementary group set.
  850.  */
  851.  
  852. static int
  853. useropen(iop, name, mode)
  854. IOBUF *iop;
  855. const char *name, *mode;
  856. {
  857.     char tbuf[BUFSIZ], *cp;
  858.     int i;
  859. #if defined(NGROUPS_MAX) && NGROUPS_MAX > 0
  860.     GETGROUPS_T groupset[NGROUPS_MAX];
  861.     int ngroups;
  862. #endif
  863.  
  864.     sprintf(tbuf, "%d %d %d %d", getuid(), geteuid(), getgid(), getegid());
  865.  
  866.     cp = tbuf + strlen(tbuf);
  867. #if defined(NGROUPS_MAX) && NGROUPS_MAX > 0
  868.     ngroups = getgroups(NGROUPS_MAX, groupset);
  869.     if (ngroups == -1)
  870.         fatal("could not find groups: %s", strerror(errno));
  871.  
  872.     for (i = 0; i < ngroups; i++) {
  873.         *cp++ = ' ';
  874.         sprintf(cp, "%d", (int) groupset[i]);
  875.         cp += strlen(cp);
  876.     }
  877. #endif
  878.     *cp++ = '\n';
  879.     *cp++ = '\0';
  880.  
  881.     i = strlen(tbuf);
  882.     spec_setup(iop, i, TRUE);
  883.     strcpy(iop->buf, tbuf);
  884.     return 0;
  885. }
  886.  
  887. /* iop_open --- handle special and regular files for input */
  888.  
  889. static IOBUF *
  890. iop_open(name, mode)
  891. const char *name, *mode;
  892. {
  893.     int openfd = INVALID_HANDLE;
  894.     int flag = 0;
  895.     struct stat buf;
  896.     IOBUF *iop;
  897.     static struct internal {
  898.         const char *name;
  899.         int compare;
  900.         int (*fp) P((IOBUF *, const char *, const char *));
  901.         IOBUF iob;
  902.     } table[] = {
  903.         { "/dev/fd/",        8,    specfdopen },
  904.         { "/dev/stdin",        10,    specfdopen },
  905.         { "/dev/stdout",    11,    specfdopen },
  906.         { "/dev/stderr",    11,    specfdopen },
  907.         { "/dev/pid",        8,    pidopen },
  908.         { "/dev/ppid",        9,    pidopen },
  909.         { "/dev/pgrpid",    11,    pidopen },
  910.         { "/dev/user",        9,    useropen },
  911.     };
  912.     int devcount = sizeof(table) / sizeof(table[0]);
  913.  
  914.     flag = str2mode(mode);
  915.  
  916.     if (STREQ(name, "-"))
  917.         openfd = fileno(stdin);
  918.     else if (do_traditional)
  919.         goto strictopen;
  920.     else if (STREQN(name, "/dev/", 5) && stat((char *) name, &buf) == -1) {
  921.         int i;
  922.  
  923.         for (i = 0; i < devcount; i++) {
  924.             if (STREQN(name, table[i].name, table[i].compare)) {
  925.                 iop = & table[i].iob;
  926.  
  927.                 if (iop->buf != NULL) {
  928.                     spec_setup(iop, 0, FALSE);
  929.                     return iop;
  930.                 } else if ((*table[i].fp)(iop, name, mode) == 0)
  931.                     return iop;
  932.                 else {
  933.                     warning("could not open %s, mode `%s'",
  934.                         name, mode);
  935.                     return NULL;
  936.                 }
  937.             }
  938.         }
  939.     }
  940.  
  941. strictopen:
  942.     if (openfd == INVALID_HANDLE)
  943.         openfd = open(name, flag, 0666);
  944.     if (openfd != INVALID_HANDLE && fstat(openfd, &buf) > 0) 
  945.         if ((buf.st_mode & S_IFMT) == S_IFDIR)
  946.             fatal("file `%s' is a directory", name);
  947.     iop = iop_alloc(openfd, name);
  948.     return iop;
  949. }
  950.  
  951. #ifndef PIPES_SIMULATED        /* real pipes */
  952.  
  953. /* wait_any --- wait for a child process, close associated pipe */
  954.  
  955. static int
  956. wait_any(interesting)
  957. int interesting;    /* pid of interest, if any */
  958. {
  959.     RETSIGTYPE (*hstat)(), (*istat)(), (*qstat)();
  960.     int pid;
  961.     int status = 0;
  962.     struct redirect *redp;
  963.     extern int errno;
  964.  
  965.     hstat = signal(SIGHUP, SIG_IGN);
  966.     istat = signal(SIGINT, SIG_IGN);
  967.     qstat = signal(SIGQUIT, SIG_IGN);
  968.     for (;;) {
  969. #ifdef HAVE_SYS_WAIT_H    /* Posix compatible sys/wait.h */
  970.         pid = wait(&status);
  971. #else
  972.         pid = wait((union wait *)&status);
  973. #endif /* NeXT */
  974.         if (interesting && pid == interesting) {
  975.             break;
  976.         } else if (pid != -1) {
  977.             for (redp = red_head; redp != NULL; redp = redp->next)
  978.                 if (pid == redp->pid) {
  979.                     redp->pid = -1;
  980.                     redp->status = status;
  981.                     if (redp->fp != NULL) {
  982.                         pclose(redp->fp);
  983.                         redp->fp = NULL;
  984.                     }
  985.                     if (redp->iop != NULL) {
  986.                         (void) iop_close(redp->iop);
  987.                         redp->iop = NULL;
  988.                     }
  989.                     break;
  990.                 }
  991.         }
  992.         if (pid == -1 && errno == ECHILD)
  993.             break;
  994.     }
  995.     signal(SIGHUP, hstat);
  996.     signal(SIGINT, istat);
  997.     signal(SIGQUIT, qstat);
  998.     return(status);
  999. }
  1000.  
  1001. /* gawk_popen --- open an IOBUF on a child process */
  1002.  
  1003. static IOBUF *
  1004. gawk_popen(cmd, rp)
  1005. char *cmd;
  1006. struct redirect *rp;
  1007. {
  1008.     int p[2];
  1009.     register int pid;
  1010.  
  1011.     /*
  1012.      * used to wait for any children to synchronize input and output,
  1013.      * but this could cause gawk to hang when it is started in a pipeline
  1014.      * and thus has a child process feeding it input (shell dependant)
  1015.      */
  1016.     /*(void) wait_any(0);*/    /* wait for outstanding processes */
  1017.  
  1018.     if (pipe(p) < 0)
  1019.         fatal("cannot open pipe \"%s\" (%s)", cmd, strerror(errno));
  1020.     if ((pid = fork()) == 0) {
  1021.         if (close(1) == -1)
  1022.             fatal("close of stdout in child failed (%s)",
  1023.                 strerror(errno));
  1024.         if (dup(p[1]) != 1)
  1025.             fatal("dup of pipe failed (%s)", strerror(errno));
  1026.         if (close(p[0]) == -1 || close(p[1]) == -1)
  1027.             fatal("close of pipe failed (%s)", strerror(errno));
  1028.         execl("/bin/sh", "sh", "-c", cmd, NULL);
  1029.         _exit(127);
  1030.     }
  1031.     if (pid == -1)
  1032.         fatal("cannot fork for \"%s\" (%s)", cmd, strerror(errno));
  1033.     rp->pid = pid;
  1034.     if (close(p[1]) == -1)
  1035.         fatal("close of pipe failed (%s)", strerror(errno));
  1036.     rp->iop = iop_alloc(p[0], cmd);
  1037.     if (rp->iop == NULL)
  1038.         (void) close(p[0]);
  1039.     return (rp->iop);
  1040. }
  1041.  
  1042. /* gawk_pclose --- close an open child pipe */
  1043.  
  1044. static int
  1045. gawk_pclose(rp)
  1046. struct redirect *rp;
  1047. {
  1048.     (void) iop_close(rp->iop);
  1049.     rp->iop = NULL;
  1050.  
  1051.     /* process previously found, return stored status */
  1052.     if (rp->pid == -1)
  1053.         return (rp->status >> 8) & 0xFF;
  1054.     rp->status = wait_any(rp->pid);
  1055.     rp->pid = -1;
  1056.     return (rp->status >> 8) & 0xFF;
  1057. }
  1058.  
  1059. #else    /* PIPES_SIMULATED */
  1060.  
  1061. /*
  1062.  * use temporary file rather than pipe
  1063.  * except if popen() provides real pipes too
  1064.  */
  1065.  
  1066. #if defined(VMS) || defined(OS2) || defined (MSDOS)
  1067.  
  1068. /* gawk_popen --- open an IOBUF on a child process */
  1069.  
  1070. static IOBUF *
  1071. gawk_popen(cmd, rp)
  1072. char *cmd;
  1073. struct redirect *rp;
  1074. {
  1075.     FILE *current;
  1076.  
  1077.     if ((current = popen(cmd, "r")) == NULL)
  1078.         return NULL;
  1079.     rp->iop = iop_alloc(fileno(current), cmd);
  1080.     if (rp->iop == NULL) {
  1081.         (void) fclose(current);
  1082.         current = NULL;
  1083.     }
  1084.     rp->ifp = current;
  1085.     return (rp->iop);
  1086. }
  1087.  
  1088. /* gawk_pclose --- close an open child pipe */
  1089.  
  1090. static int
  1091. gawk_pclose(rp)
  1092. struct redirect *rp;
  1093. {
  1094.     int rval, aval, fd = rp->iop->fd;
  1095.  
  1096.     rp->iop->fd = dup(fd);      /* kludge to allow close() + pclose() */
  1097.     rval = iop_close(rp->iop);
  1098.     rp->iop = NULL;
  1099.     aval = pclose(rp->ifp);
  1100.     rp->ifp = NULL;
  1101.     return (rval < 0 ? rval : aval);
  1102. }
  1103. #else    /* not (VMS || OS2 || MSDOS) */
  1104.  
  1105. static struct pipeinfo {
  1106.     char *command;
  1107.     char *name;
  1108. } pipes[_NFILE];
  1109.  
  1110. /* gawk_popen --- open an IOBUF on a child process */
  1111.  
  1112. static IOBUF *
  1113. gawk_popen(cmd, rp)
  1114. char *cmd;
  1115. struct redirect *rp;
  1116. {
  1117.     extern char *strdup P((const char *));
  1118.     int current;
  1119.     char *name;
  1120.     static char cmdbuf[256];
  1121.  
  1122.     /* get a name to use */
  1123.     if ((name = tempnam(".", "pip")) == NULL)
  1124.         return NULL;
  1125.     sprintf(cmdbuf, "%s > %s", cmd, name);
  1126.     system(cmdbuf);
  1127.     if ((current = open(name, O_RDONLY)) == INVALID_HANDLE)
  1128.         return NULL;
  1129.     pipes[current].name = name;
  1130.     pipes[current].command = strdup(cmd);
  1131.     rp->iop = iop_alloc(current, name);
  1132.     if (rp->iop == NULL)
  1133.         (void) close(current);
  1134.     return (rp->iop);
  1135. }
  1136.  
  1137. /* gawk_pclose --- close an open child pipe */
  1138.  
  1139. static int
  1140. gawk_pclose(rp)
  1141. struct redirect *rp;
  1142. {
  1143.     int cur = rp->iop->fd;
  1144.     int rval;
  1145.  
  1146.     rval = iop_close(rp->iop);
  1147.     rp->iop = NULL;
  1148.  
  1149.     /* check for an open file  */
  1150.     if (pipes[cur].name == NULL)
  1151.         return -1;
  1152.     unlink(pipes[cur].name);
  1153.     free(pipes[cur].name);
  1154.     pipes[cur].name = NULL;
  1155.     free(pipes[cur].command);
  1156.     return rval;
  1157. }
  1158. #endif    /* not (VMS || OS2 || MSDOS) */
  1159.  
  1160. #endif    /* PIPES_SIMULATED */
  1161.  
  1162. /* do_getline --- read in a line, into var and with redirection, as needed */
  1163.  
  1164. NODE *
  1165. do_getline(tree)
  1166. NODE *tree;
  1167. {
  1168.     struct redirect *rp = NULL;
  1169.     IOBUF *iop;
  1170.     int cnt = EOF;
  1171.     char *s = NULL;
  1172.     int errcode;
  1173.  
  1174.     while (cnt == EOF) {
  1175.         if (tree->rnode == NULL) {     /* no redirection */
  1176.             iop = nextfile(FALSE);
  1177.             if (iop == NULL)        /* end of input */
  1178.                 return tmp_number((AWKNUM) 0.0);
  1179.         } else {
  1180.             int redir_error = 0;
  1181.  
  1182.             rp = redirect(tree->rnode, &redir_error);
  1183.             if (rp == NULL && redir_error) { /* failed redirect */
  1184.                 if (! do_traditional) {
  1185.                     s = strerror(redir_error);
  1186.  
  1187.                     unref(ERRNO_node->var_value);
  1188.                     ERRNO_node->var_value =
  1189.                         make_string(s, strlen(s));
  1190.                 }
  1191.                 return tmp_number((AWKNUM) -1.0);
  1192.             }
  1193.             iop = rp->iop;
  1194.             if (iop == NULL)        /* end of input */
  1195.                 return tmp_number((AWKNUM) 0.0);
  1196.         }
  1197.         errcode = 0;
  1198.         cnt = get_a_record(&s, iop, RS->stptr[0], RS_regexp, &errcode);
  1199.         if (errcode != 0) {
  1200.             if (! do_traditional) {
  1201.                 s = strerror(errcode);
  1202.  
  1203.                 unref(ERRNO_node->var_value);
  1204.                 ERRNO_node->var_value = make_string(s, strlen(s));
  1205.             }
  1206.             return tmp_number((AWKNUM) -1.0);
  1207.         }
  1208.         if (cnt == EOF) {
  1209.             if (rp != NULL) {
  1210.                 /*
  1211.                  * Don't do iop_close() here if we are
  1212.                  * reading from a pipe; otherwise
  1213.                  * gawk_pclose will not be called.
  1214.                  */
  1215.                 if ((rp->flag & RED_PIPE) == 0) {
  1216.                     (void) iop_close(iop);
  1217.                     rp->iop = NULL;
  1218.                 }
  1219.                 rp->flag |= RED_EOF;    /* sticky EOF */
  1220.                 return tmp_number((AWKNUM) 0.0);
  1221.             } else
  1222.                 continue;    /* try another file */
  1223.         }
  1224.         if (rp == NULL) {
  1225.             NR++;
  1226.             FNR++;
  1227.         }
  1228.         if (tree->lnode == NULL)    /* no optional var. */
  1229.             set_record(s, cnt, TRUE);
  1230.         else {            /* assignment to variable */
  1231.             Func_ptr after_assign = NULL;
  1232.             NODE **lhs;
  1233.  
  1234.             lhs = get_lhs(tree->lnode, &after_assign);
  1235.             unref(*lhs);
  1236.             *lhs = make_string(s, strlen(s));
  1237.             (*lhs)->flags |= MAYBE_NUM;
  1238.             /* we may have to regenerate $0 here! */
  1239.             if (after_assign != NULL)
  1240.                 (*after_assign)();
  1241.         }
  1242.     }
  1243.     return tmp_number((AWKNUM) 1.0);
  1244. }
  1245.  
  1246. /* pathopen --- pathopen with default file extension handling */
  1247.  
  1248. int
  1249. pathopen(file)
  1250. const char *file;
  1251. {
  1252.     int fd = do_pathopen(file);
  1253.  
  1254. #ifdef DEFAULT_FILETYPE
  1255.     if (! do_traditional && fd <= INVALID_HANDLE) {
  1256.         char *file_awk;
  1257.         int save = errno;
  1258. #ifdef VMS
  1259.         int vms_save = vaxc$errno;
  1260. #endif
  1261.  
  1262.         /* append ".awk" and try again */
  1263.         emalloc(file_awk, char *, strlen(file) +
  1264.             sizeof(DEFAULT_FILETYPE) + 1, "pathopen");
  1265.         sprintf(file_awk, "%s%s", file, DEFAULT_FILETYPE);
  1266.         fd = do_pathopen(file_awk);
  1267.         free(file_awk);
  1268.         if (fd <= INVALID_HANDLE) {
  1269.             errno = save;
  1270. #ifdef VMS
  1271.             vaxc$errno = vms_save;
  1272. #endif
  1273.         }
  1274.     }
  1275. #endif    /*DEFAULT_FILETYPE*/
  1276.  
  1277.     return fd;
  1278. }
  1279.  
  1280. /* do_pathopen --- search $AWKPATH for source file */
  1281.  
  1282. static int
  1283. do_pathopen(file)
  1284. const char *file;
  1285. {
  1286.     static const char *savepath = NULL;
  1287.     static int first = TRUE;
  1288.     const char *awkpath;
  1289.     char *cp, trypath[BUFSIZ];
  1290.     int fd;
  1291.  
  1292.     if (STREQ(file, "-"))
  1293.         return (0);
  1294.  
  1295.     if (do_traditional)
  1296.         return (devopen(file, "r"));
  1297.  
  1298.     if (first) {
  1299.         first = FALSE;
  1300.         if ((awkpath = getenv("AWKPATH")) != NULL && *awkpath)
  1301.             savepath = awkpath;    /* used for restarting */
  1302.         else
  1303.             savepath = defpath;
  1304.     }
  1305.     awkpath = savepath;
  1306.  
  1307.     /* some kind of path name, no search */
  1308.     if (ispath(file))
  1309.         return (devopen(file, "r"));
  1310.  
  1311.     do {
  1312.         trypath[0] = '\0';
  1313.         /* this should take into account limits on size of trypath */
  1314.         for (cp = trypath; *awkpath && *awkpath != envsep; )
  1315.             *cp++ = *awkpath++;
  1316.  
  1317.         if (cp != trypath) {    /* nun-null element in path */
  1318.             /* add directory punctuation only if needed */
  1319.             if (! isdirpunct(*(cp-1)))
  1320.                 *cp++ = '/';
  1321.             /* append filename */
  1322.             strcpy(cp, file);
  1323.         } else
  1324.             strcpy(trypath, file);
  1325.         if ((fd = devopen(trypath, "r")) > INVALID_HANDLE)
  1326.             return (fd);
  1327.  
  1328.         /* no luck, keep going */
  1329.         if(*awkpath == envsep && awkpath[1] != '\0')
  1330.             awkpath++;    /* skip colon */
  1331.     } while (*awkpath != '\0');
  1332.     /*
  1333.      * You might have one of the awk paths defined, WITHOUT the current
  1334.      * working directory in it. Therefore try to open the file in the
  1335.      * current directory.
  1336.      */
  1337.     return (devopen(file, "r"));
  1338. }
  1339.  
  1340. #ifdef TEST
  1341. int bufsize = 8192;
  1342.  
  1343. void
  1344. fatal(s)
  1345. char *s;
  1346. {
  1347.     printf("%s\n", s);
  1348.     exit(1);
  1349. }
  1350. #endif
  1351.  
  1352. /* iop_alloc --- allocate an IOBUF structure for an open fd */
  1353.  
  1354. IOBUF *
  1355. iop_alloc(fd, name)
  1356. int fd;
  1357. const char *name;
  1358. {
  1359.     IOBUF *iop;
  1360.     struct stat sbuf;
  1361.  
  1362.     if (fd == INVALID_HANDLE)
  1363.         return NULL;
  1364.     emalloc(iop, IOBUF *, sizeof(IOBUF), "iop_alloc");
  1365.     iop->flag = 0;
  1366.     if (isatty(fd))
  1367.         iop->flag |= IOP_IS_TTY;
  1368.     iop->size = optimal_bufsize(fd, & sbuf);
  1369.     if (do_lint && S_ISREG(sbuf.st_mode) && sbuf.st_size == 0)
  1370.         warning("data file `%s' is empty", name);
  1371.     iop->secsiz = -2;
  1372.     errno = 0;
  1373.     iop->fd = fd;
  1374.     iop->off = iop->buf = NULL;
  1375.     iop->cnt = 0;
  1376.     iop->name = name;
  1377.     return iop;
  1378. }
  1379.  
  1380. /*
  1381.  * get_a_record:
  1382.  * Get the next record.  Uses a "split buffer" where the latter part is
  1383.  * the normal read buffer and the head part is an "overflow" area that is used
  1384.  * when a record spans the end of the normal buffer, in which case the first
  1385.  * part of the record is copied into the overflow area just before the
  1386.  * normal buffer.  Thus, the eventual full record can be returned as a
  1387.  * contiguous area of memory with a minimum of copying.  The overflow area
  1388.  * is expanded as needed, so that records are unlimited in length.
  1389.  * We also mark both the end of the buffer and the end of the read() with
  1390.  * a sentinel character (the current record separator) so that the inside
  1391.  * loop can run as a single test.
  1392.  *
  1393.  * Note that since we know or can compute the end of the read and the end
  1394.  * of the buffer, the sentinel character does not get in the way of regexp
  1395.  * based searching, since we simply search up to that character, but not
  1396.  * including it.
  1397.  */
  1398.  
  1399. static int
  1400. get_a_record(out, iop, grRS, RSre, errcode)
  1401. char **out;        /* pointer to pointer to data */
  1402. IOBUF *iop;        /* input IOP */
  1403. register int grRS;    /* first char in RS->stptr */
  1404. Regexp *RSre;        /* regexp for RS */
  1405. int *errcode;        /* pointer to error variable */
  1406. {
  1407.     register char *bp = iop->off;
  1408.     char *bufend;
  1409.     char *start = iop->off;            /* beginning of record */
  1410.     char rs;
  1411.     static Regexp *RS_null_re = NULL;
  1412.     Regexp *rsre = NULL;
  1413.     int continuing = FALSE;        /* used for re matching */
  1414.     int onecase;
  1415.  
  1416. #define set_RT_to_null() \
  1417.     (void)(! do_traditional && (unref(RT_node->var_value), \
  1418.                RT_node->var_value = Nnull_string))
  1419.  
  1420. #define set_RT(str, len) \
  1421.     (void)(! do_traditional && (unref(RT_node->var_value), \
  1422.                RT_node->var_value = make_string(str, len)))
  1423.  
  1424.     /* first time through */
  1425.     if (RS_null_re == NULL) {
  1426.         RS_null_re = make_regexp("\n\n+", 3, TRUE, TRUE);
  1427.         if (RS_null_re == NULL)
  1428.             fatal("internal error: file `%s', line %d\n",
  1429.                 __FILE__, __LINE__);
  1430.     }
  1431.  
  1432.     if (iop->cnt == EOF) {    /* previous read hit EOF */
  1433.         *out = NULL;
  1434.         set_RT_to_null();
  1435.         return EOF;
  1436.     }
  1437.  
  1438.     if (grRS == FALSE)    /* special case:  RS == "" */
  1439.         rs = '\n';
  1440.     else
  1441.         rs = (char) grRS;
  1442.  
  1443.     onecase = (IGNORECASE && isalpha(rs));
  1444.     if (onecase)
  1445.         rs = casetable[rs];
  1446.  
  1447.     /* set up sentinel */
  1448.     if (iop->buf) {
  1449.         bufend = iop->buf + iop->size + iop->secsiz;
  1450.         *bufend = rs;        /* add sentinel to buffer */
  1451.     } else
  1452.         bufend = NULL;
  1453.  
  1454.     for (;;) {    /* break on end of record, read error or EOF */
  1455. /* buffer mgmt, chunk #1 */
  1456.         /*
  1457.          * Following code is entered on the first call of this routine
  1458.          * for a new iop, or when we scan to the end of the buffer.
  1459.          * In the latter case, we copy the current partial record to
  1460.          * the space preceding the normal read buffer.  If necessary,
  1461.          * we expand this space.  This is done so that we can return
  1462.          * the record as a contiguous area of memory.
  1463.          */
  1464.         if ((iop->flag & IOP_IS_INTERNAL) == 0 && bp >= bufend) {
  1465.             char *oldbuf = NULL;
  1466.             char *oldsplit = iop->buf + iop->secsiz;
  1467.             long len;    /* record length so far */
  1468.  
  1469.             len = bp - start;
  1470.             if (len > iop->secsiz) {
  1471.                 /* expand secondary buffer */
  1472.                 if (iop->secsiz == -2)
  1473.                     iop->secsiz = 256;
  1474.                 while (len > iop->secsiz)
  1475.                     iop->secsiz *= 2;
  1476.                 oldbuf = iop->buf;
  1477.                 emalloc(iop->buf, char *,
  1478.                     iop->size+iop->secsiz+2, "get_a_record");
  1479.                 bufend = iop->buf + iop->size + iop->secsiz;
  1480.                 *bufend = rs;
  1481.             }
  1482.             if (len > 0) {
  1483.                 char *newsplit = iop->buf + iop->secsiz;
  1484.  
  1485.                 if (start < oldsplit) {
  1486.                     memcpy(newsplit - len, start,
  1487.                             oldsplit - start);
  1488.                     memcpy(newsplit - (bp - oldsplit),
  1489.                             oldsplit, bp - oldsplit);
  1490.                 } else
  1491.                     memcpy(newsplit - len, start, len);
  1492.             }
  1493.             bp = iop->end = iop->off = iop->buf + iop->secsiz;
  1494.             start = bp - len;
  1495.             if (oldbuf != NULL) {
  1496.                 free(oldbuf);
  1497.                 oldbuf = NULL;
  1498.             }
  1499.         }
  1500. /* buffer mgmt, chunk #2 */
  1501.         /*
  1502.          * Following code is entered whenever we have no more data to
  1503.          * scan.  In most cases this will read into the beginning of
  1504.          * the main buffer, but in some cases (terminal, pipe etc.)
  1505.          * we may be doing smallish reads into more advanced positions.
  1506.          */
  1507.         if (bp >= iop->end) {
  1508.             if ((iop->flag & IOP_IS_INTERNAL) != 0) {
  1509.                 iop->cnt = EOF;
  1510.                 break;
  1511.             }
  1512.             iop->cnt = read(iop->fd, iop->end, bufend - iop->end);
  1513.             if (iop->cnt == -1) {
  1514.                 if (! do_traditional && errcode != NULL) {
  1515.                     *errcode = errno;
  1516.                     iop->cnt = EOF;
  1517.                     break;
  1518.                 } else
  1519.                     fatal("error reading input file `%s': %s",
  1520.                         iop->name, strerror(errno));
  1521.             } else if (iop->cnt == 0) {
  1522.                 /*
  1523.                  * hit EOF before matching RS, so end
  1524.                  * the record and set RT to ""
  1525.                  */
  1526.                 iop->cnt = EOF;
  1527.                 /* see comments below about this test */
  1528.                 if (! continuing) {
  1529.                     set_RT_to_null();
  1530.                     break;
  1531.                 }
  1532.             }
  1533.             if (iop->cnt != EOF) {
  1534.                 iop->end += iop->cnt;
  1535.                 *iop->end = rs;        /* reset the sentinel */
  1536.             }
  1537.         }
  1538. /* buffers are now setup and filled with data */
  1539. /* search for RS, #1, regexp based, or RS = "" */
  1540.         /*
  1541.          * Attempt to simplify the code a bit. The case where
  1542.          * RS = "" can also be described by a regexp, RS = "\n\n+".
  1543.          * The buffer managment and searching code can thus now
  1544.          * use a common case (the one for regexps) both when RS is
  1545.          * a regexp, and when RS = "". This particularly benefits
  1546.          * us for keeping track of how many newlines were matched
  1547.          * in order to set RT.
  1548.          */
  1549.         if (! do_traditional && RSre != NULL)    /* regexp */
  1550.             rsre = RSre;
  1551.         else if (grRS == FALSE)        /* RS = "" */
  1552.             rsre = RS_null_re;
  1553.         else
  1554.             rsre = NULL;
  1555.  
  1556.         /*
  1557.          * Look for regexp match of RS.  Non-match conditions are:
  1558.          *    1. No match at all
  1559.          *    2. Match of a null string
  1560.          *    3. Match ends at exact end of buffer
  1561.          * Number 3 is subtle; we have to add more to the buffer
  1562.          * in case the match would have extended further into the
  1563.          * file, since regexp match by definition always matches the
  1564.          * longest possible match.
  1565.          *
  1566.          * It is even more subtle than you might think. Suppose
  1567.          * the re matches at exactly the end of file. We don't know
  1568.          * that until we try to add more to the buffer. Thus, we
  1569.          * set a flag to indicate, that if eof really does happen,
  1570.          * don't break early.
  1571.          */
  1572.         continuing = FALSE;
  1573.         if (rsre != NULL) {
  1574.         again:
  1575.             /* cases 1 and 2 are simple, just keep going */
  1576.             if (research(rsre, start, 0, iop->end - start, TRUE) == -1
  1577.                 || RESTART(rsre, start) == REEND(rsre, start)) {
  1578.                 bp = iop->end;
  1579.                 continue;
  1580.             }
  1581.             /* case 3, regex match at exact end */
  1582.             if (start + REEND(rsre, start) >= iop->end) {
  1583.                 if (iop->cnt != EOF) {
  1584.                     bp = iop->end;
  1585.                     continuing = TRUE;
  1586.                     continue;
  1587.                 }
  1588.             }
  1589.             /* got a match! */
  1590.             /*
  1591.              * Leading newlines at the beginning of the file
  1592.              * should be ignored. Whew!
  1593.              */
  1594.             if (grRS == FALSE && RESTART(rsre, start) == 0) {
  1595.                 start += REEND(rsre, start);
  1596.                 goto again;
  1597.             }
  1598.             bp = start + RESTART(rsre, start);
  1599.             set_RT(bp, REEND(rsre, start) - RESTART(rsre, start));
  1600.             *bp = '\0';
  1601.             iop->off = start + REEND(rsre, start);
  1602.             break;
  1603.         }
  1604. /* search for RS, #2, RS = <single char> */
  1605.         if (onecase) {
  1606.             while (casetable[*bp++] != rs)
  1607.                 continue;
  1608.         } else {
  1609.             while (*bp++ != rs)
  1610.                 continue;
  1611.         }
  1612.         set_RT(bp - 1, 1);
  1613.  
  1614.         if (bp <= iop->end)
  1615.             break;
  1616.         else
  1617.             bp--;
  1618.  
  1619.         if ((iop->flag & IOP_IS_INTERNAL) != 0)
  1620.             iop->cnt = bp - start;
  1621.     }
  1622.     if (iop->cnt == EOF
  1623.         && (((iop->flag & IOP_IS_INTERNAL) != 0) || start == bp)) {
  1624.         *out = NULL;
  1625.         set_RT_to_null();
  1626.         return EOF;
  1627.     }
  1628.  
  1629.     if (do_traditional || rsre == NULL) {
  1630.         char *bstart;
  1631.  
  1632.         bstart = iop->off = bp;
  1633.         bp--;
  1634.         if (onecase ? casetable[*bp] != rs : *bp != rs) {
  1635.             bp++;
  1636.             bstart = bp;
  1637.         }
  1638.         *bp = '\0';
  1639.     } else if (grRS == FALSE && iop->cnt == EOF) {
  1640.         /*
  1641.          * special case, delete trailing newlines,
  1642.          * should never be more than one.
  1643.          */
  1644.         while (bp[-1] == '\n')
  1645.             bp--;
  1646.         *bp = '\0';
  1647.     }
  1648.  
  1649.     *out = start;
  1650.     return bp - start;
  1651. }
  1652.  
  1653. #ifdef TEST
  1654. int
  1655. main(argc, argv)
  1656. int argc;
  1657. char *argv[];
  1658. {
  1659.     IOBUF *iop;
  1660.     char *out;
  1661.     int cnt;
  1662.     char rs[2];
  1663.  
  1664.     rs[0] = '\0';
  1665.     if (argc > 1)
  1666.         bufsize = atoi(argv[1]);
  1667.     if (argc > 2)
  1668.         rs[0] = *argv[2];
  1669.     iop = iop_alloc(0, "stdin");
  1670.     while ((cnt = get_a_record(&out, iop, rs[0], NULL, NULL)) > 0) {
  1671.         fwrite(out, 1, cnt, stdout);
  1672.         fwrite(rs, 1, 1, stdout);
  1673.     }
  1674.     return 0;
  1675. }
  1676. #endif
  1677.  
  1678. /* set_RS --- update things as appropriate when RS is set */
  1679.  
  1680. void
  1681. set_RS()
  1682. {
  1683.     static NODE *save_rs = NULL;
  1684.  
  1685.     if (save_rs && cmp_nodes(RS_node->var_value, save_rs) == 0)
  1686.         return;
  1687.     unref(save_rs);
  1688.     save_rs = dupnode(RS_node->var_value);
  1689.     RS_is_null = FALSE;
  1690.     RS = force_string(RS_node->var_value);
  1691.     if (RS_regexp != NULL) {
  1692.         refree(RS_regexp);
  1693.         RS_regexp = NULL;
  1694.     }
  1695.     if (RS->stlen == 0)
  1696.         RS_is_null = TRUE;
  1697.     else if (RS->stlen > 1)
  1698.         RS_regexp = make_regexp(RS->stptr, RS->stlen, IGNORECASE, TRUE);
  1699.  
  1700.     set_FS_if_not_FIELDWIDTHS();
  1701. }
  1702.